package com.eelpo.framework;

import java.net.InetSocketAddress;
import java.util.HashMap;
import java.util.Map;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
import java.util.concurrent.TimeUnit;

import org.jboss.netty.bootstrap.ServerBootstrap;
import org.jboss.netty.channel.ChannelPipelineFactory;
import org.jboss.netty.channel.socket.nio.NioServerSocketChannelFactory;
import org.jboss.netty.handler.execution.ExecutionHandler;
import org.jboss.netty.handler.execution.OrderedMemoryAwareThreadPoolExecutor;
import org.jboss.netty.util.HashedWheelTimer;

import com.eelpo.framework.socket.SocketPipelineFactory;
import com.eelpo.framework.socket.handler.SocketIdleStateHandler;
import com.eelpo.framework.socket.handler.SocketProcessHandler;
import com.eelpo.framework.socket.listener.SocketContextListener;
import com.eelpo.framework.socket.listener.SocketIdleListener;
import com.eelpo.framework.socket.listener.SocketRequestListener;
import com.eelpo.framework.socket.listener.SocketResponseListener;
import com.eelpo.framework.socket.listener.SocketSessionListener;
import com.eelpo.framework.socket.session.SocketSessionCache;

/**
 * 游戏服务器基类
 * 
 * @author <a href="mailto:whz-work@163.com">汪洪州</a>
 * 
 * @since 1.0 Create on May 30, 2012
 */
public class GameServer {

	// property
	private int port = 8001;
	private String name = "default";

	// listeners
	private GameServerListener gameServerListener;
	private SocketIdleListener socketIdleListener;
	private SocketSessionListener socketSessionListener;
	private SocketContextListener socketContextListener;
	private SocketRequestListener socketRequestListener;
	private SocketResponseListener socketResponseListener;

	// handlers
	private ExecutionHandler executionHandler;
	private SocketProcessHandler socketProcessHandler;
	private SocketIdleStateHandler socketIdleStateHandler;

	// bootstrap
	private int workerCount;
	private Map<String, Object> options;
	private ExecutorService bossExecutor;
	private ExecutorService workerExecutor;
	private ServerBootstrap serverBootstrap;
	private ChannelPipelineFactory channelPipelineFactory;

	public GameServer() {

	}

	public GameServer(int port, String name) {
		this.port = port;
		this.name = name;
	}

	public GameServer(int port, String name, GameServerListener gameServerListener) {
		this.port = port;
		this.name = name;
		this.gameServerListener = gameServerListener;
	}

	public void init() {
		if (gameServerListener != null) {
			gameServerListener.init(this);
		}
	}

	public void start() {
		SocketSessionCache.setSessionListener(getSocketSessionListener());
		getServerBootstrap().bind(new InetSocketAddress(getPort()));
		if (gameServerListener != null) {
			gameServerListener.start(this);
		}
	}

	public void stop() {
		if (gameServerListener != null) {
			gameServerListener.stop(this);
		}
	}

	public void destroy() {
		getServerBootstrap().releaseExternalResources();
		if (gameServerListener != null) {
			gameServerListener.destroy(this);
		}
	}

	public int getPort() {
		return port;
	}

	public void setPort(int port) {
		this.port = port;
	}

	public String getName() {
		return name;
	}

	public void setName(String name) {
		this.name = name;
	}

	public GameServerListener getGameServerListener() {
		return gameServerListener;
	}

	public void setGameServerListener(GameServerListener gameServerListener) {
		this.gameServerListener = gameServerListener;
	}

	public SocketIdleListener getSocketIdleListener() {
		return socketIdleListener;
	}

	public void setSocketIdleListener(SocketIdleListener socketIdleListener) {
		this.socketIdleListener = socketIdleListener;
	}

	public SocketSessionListener getSocketSessionListener() {
		return socketSessionListener;
	}

	public void setSocketSessionListener(SocketSessionListener socketSessionListener) {
		this.socketSessionListener = socketSessionListener;
	}

	public SocketContextListener getSocketContextListener() {
		return socketContextListener;
	}

	public void setSocketContextListener(SocketContextListener socketContextListener) {
		this.socketContextListener = socketContextListener;
	}

	public SocketRequestListener getSocketRequestListener() {
		return socketRequestListener;
	}

	public void setSocketRequestListener(SocketRequestListener socketRequestListener) {
		this.socketRequestListener = socketRequestListener;
	}

	public SocketResponseListener getSocketResponseListener() {
		return socketResponseListener;
	}

	public void setSocketResponseListener(SocketResponseListener socketResponseListener) {
		this.socketResponseListener = socketResponseListener;
	}

	public ExecutionHandler getExecutionHandler() {
		if (executionHandler == null) {
			executionHandler = getDefaultExecutionHandler();
		}
		return executionHandler;
	}

	public void setExecutionHandler(ExecutionHandler executionHandler) {
		this.executionHandler = executionHandler;
	}

	public SocketProcessHandler getSocketProcessHandler() {
		if (socketProcessHandler == null) {
			socketProcessHandler = getDefaultSocketProcessHandler();
		}
		return socketProcessHandler;
	}

	public void setSocketProcessHandler(SocketProcessHandler socketProcessHandler) {
		this.socketProcessHandler = socketProcessHandler;
	}

	public SocketIdleStateHandler getSocketIdleStateHandler() {
		if (socketIdleStateHandler == null) {
			socketIdleStateHandler = getDefaultSocketIdleStateHandler();
		}
		return socketIdleStateHandler;
	}

	public void setSocketIdleStateHandler(SocketIdleStateHandler socketIdleStateHandler) {
		this.socketIdleStateHandler = socketIdleStateHandler;
	}

	public Map<String, Object> getOptions() {
		if (options == null) {
			options = getDefaultOptions();
		}
		return options;
	}

	public void setOptions(Map<String, Object> options) {
		this.options = options;
	}

	public ServerBootstrap getServerBootstrap() {
		if (serverBootstrap == null) {
			serverBootstrap = getDefaultServerBootstrap();
		}
		return serverBootstrap;
	}

	public void setServerBootstrap(ServerBootstrap serverBootstrap) {
		this.serverBootstrap = serverBootstrap;
	}

	public ChannelPipelineFactory getChannelPipelineFactory() {
		if (channelPipelineFactory == null) {
			channelPipelineFactory = getDefaultChannelPipelineFactory();
		}
		return channelPipelineFactory;
	}

	public void setChannelPipelineFactory(ChannelPipelineFactory channelPipelineFactory) {
		this.channelPipelineFactory = channelPipelineFactory;
	}

	public int getWorkerCount() {
		if (workerCount == 0) {
			workerCount = getDefaultWorkerCount();
		}
		return workerCount;
	}

	public void setWorkerCount(int workerCount) {
		this.workerCount = workerCount;
	}

	public ExecutorService getBossExecutor() {
		if (bossExecutor == null) {
			bossExecutor = getDefaultBossExecutor();
		}
		return bossExecutor;
	}

	public void setBossExecutor(ExecutorService bossExecutor) {
		this.bossExecutor = bossExecutor;
	}

	public ExecutorService getWorkerExecutor() {
		if (workerExecutor == null) {
			workerExecutor = getDefaultWorkerExecutor();
		}
		return workerExecutor;
	}

	public void setWorkerExecutor(ExecutorService workerExecutor) {
		this.workerExecutor = workerExecutor;
	}

	protected ServerBootstrap getDefaultServerBootstrap() {
		ServerBootstrap serverBootstrap = new ServerBootstrap(new NioServerSocketChannelFactory(getBossExecutor(), getWorkerExecutor(), getWorkerCount()));
		serverBootstrap.setOptions(getOptions());
		serverBootstrap.setPipelineFactory(getChannelPipelineFactory());
		return serverBootstrap;
	}

	protected int getDefaultWorkerCount() {
		return Runtime.getRuntime().availableProcessors() * 2;
	}

	protected ExecutorService getDefaultBossExecutor() {
		return Executors.newCachedThreadPool();
	}

	protected ExecutorService getDefaultWorkerExecutor() {
		return Executors.newCachedThreadPool();
	}

	protected Map<String, Object> getDefaultOptions() {
		Map<String, Object> options = new HashMap<String, Object>();
		options.put("child.keepAlive", Boolean.TRUE);
		options.put("child.tcpNoDelay", Boolean.TRUE);
		options.put("child.reuseAddress", Boolean.TRUE);
		return options;
	}

	protected ChannelPipelineFactory getDefaultChannelPipelineFactory() {
		return new SocketPipelineFactory(getExecutionHandler(), getSocketProcessHandler(), getSocketIdleStateHandler());
	}

	protected ExecutionHandler getDefaultExecutionHandler() {
		return new ExecutionHandler(new OrderedMemoryAwareThreadPoolExecutor(500, 0L, 0L));
	}

	protected SocketProcessHandler getDefaultSocketProcessHandler() {
		return new SocketProcessHandler(getSocketContextListener(), getSocketRequestListener(), getSocketResponseListener());
	}

	public SocketIdleStateHandler getDefaultSocketIdleStateHandler() {
		return new SocketIdleStateHandler(new HashedWheelTimer(10, TimeUnit.SECONDS, 512), 300, 0, 0);
	}

}
